%{
/* C definitions of things used in grammar */
    #include "glodef.h"
    #define __F3_PARSER_Y__ 1

    #include "glovar.h"
    /* glovar defines flags, Re, alpha, beta */
    #include <math.h>
    #ifndef M_PI
        #define M_PI        3.1415926535897932384626433832795
    #endif
    #define YYSTYPE double
    #define YYERROR_VERBOSE
    int yylex (void);
    void yyerror (char const *);
    static double vars[4];
    static double vals[3];
%}
/* definitions of grammar symbols start here */

%token  NUM
%token  LT          /*  "<"         */
%token  LE          /*  "<="        */
%token  GT          /*  ">"         */
%token  GE          /*  ">="        */
%token  EQ          /*  "=" or "==" */
%token  NE          /*  "!="        */

%left    '-' '+'
%left    '*' '/'
%left    NEG
%right   '^'

%%  /* end of definitions.  grammar rules start here */

/* scalar field has 1 and vector field has 3 components */
input:  expr                            { vals[0] = $1;                     }
    |   '[' expr ',' expr ',' expr ']'  { vals[0]=$2;vals[1]=$4;vals[2]=$6; }
    |   expr '*' '[' expr ',' expr ',' expr ']'  { vals[0]=$1*$4;vals[1]=$1*$6;vals[2]=$1*$8; }
    | '[' expr ',' expr ',' expr ']' '+' expr '*' '[' expr ',' expr ',' expr ']'  
           { vals[0]=$2+$9*$12;vals[1]=$4+$9*$14;vals[2]=$6+$9*$16; }
    | '[' expr ',' expr ',' expr ']' '-' expr '*' '[' expr ',' expr ',' expr ']'  
           { vals[0]=$2-$9*$12;vals[1]=$4-$9*$14;vals[2]=$6-$9*$16; }
;

expr:   NUM                                 { $$ = $1;              }
    |   var                                 { $$ = $1;              }
    |   expr '+' expr                       { $$ = $1 + $3;         }
    |   expr '-' expr                       { $$ = $1 - $3;         }
    |   expr '*' expr                       { $$ = $1 * $3;         }
    |   expr '/' expr                       { $$ = $1 / $3;         }
    |   '-' expr         %prec NEG          { $$ = -$2;             }
    |   expr '^' expr                       { $$ = pow ($1, $3);    }
    |   '(' expr ')'                        { $$ = $2;              }
    |   '{' expr LT expr '?' expr ':' expr '}'  { $$ = $2<$4?$6:$8;     }
    |   '{' expr LE expr '?' expr ':' expr '}'  { $$ = $2<=$4?$6:$8;    }
    |   '{' expr GT expr '?' expr ':' expr '}'  { $$ = $2>$4?$6:$8;     }
    |   '{' expr GE expr '?' expr ':' expr '}'  { $$ = $2>=$4?$6:$8;    }
    |   '{' expr EQ expr '?' expr ':' expr '}'  { $$ = $2==$4?$6:$8;    }
    |   '{' expr NE expr '?' expr ':' expr '}'  { $$ = $2!=$4?$6:$8;    }
    |   '{' expr '?' expr ':' expr '}'      { $$ = $2 ? $4:$6;}
    |   'a' 'd' 'v'                         { $$ = flags.advection ? 1.0 : 0.0; }
    |   'p' 'i'                             { $$ = M_PI;            }
    |   'P' 'i'                             { $$ = M_PI;            }
    |   'P' 'I'                             { $$ = M_PI;            }
    |   'r' 'e'                             { $$ = Re;              }
    |   'R' 'e'                             { $$ = Re;              }
    |   'R' 'E'                             { $$ = Re;              }
    |   'a' 'l' 'p' 'h' 'a'                 { $$ = alpha;           }
    |   'b' 'e' 't' 'a'                     { $$ = beta;            }
    |   'l' 'n' '(' expr ')'                { $$ = log($4);         }
    |   'l' 'o' 'g' '(' expr ')'            { $$ = log10($5);       }
    |   's' 'i' 'n' '(' expr ')'            { $$ = sin($5);         }
    |   'c' 'o' 's' '(' expr ')'            { $$ = cos($5);         }
    |   't' 'a' 'n' '(' expr ')'            { $$ = tan($5);         }
    |   'c' 'o' 't' '(' expr ')'            { $$ = 1.0/tan($5);     }
    |   'e' 'x' 'p' '(' expr ')'            { $$ = exp($5);         }
    |   'a' 'b' 's' '(' expr ')'            { $$ = fabs($5);        }
    |   's' 'q' 'r' '(' expr ')'            { $$ = ($5)*($5);       }
    |   'f' 'a' 'b' 's' '(' expr ')'        { $$ = fabs($6);        }
    |   'a' 's' 'i' 'n' '(' expr ')'        { $$ = asin($6);        }
    |   'a' 'c' 'o' 's' '(' expr ')'        { $$ = acos($6);        }
    |   'a' 't' 'a' 'n' '(' expr ')'        { $$ = atan($6);        }
    |   'a' 'c' 'o' 't' '(' expr ')'        { $$ = atan(1.0/$6);    }
    |   's' 'i' 'n' 'h' '(' expr ')'        { $$ = sinh($6);        }
    |   'c' 'o' 's' 'h' '(' expr ')'        { $$ = cosh($6);        }
    |   't' 'a' 'n' 'h' '(' expr ')'        { $$ = tanh($6);        }
    |   's' 'q' 'r' 't' '(' expr ')'        { $$ = sqrt($6);        }
    |   'm' 'a' 'x' '(' expr ',' expr ')'   { $$ = fmax($5,$7);     }
    |   'm' 'i' 'n' '(' expr ',' expr ')'   { $$ = fmin($5,$7);     }
;

var:    'x'     { $$ = vars[0]; }
    |   'X'     { $$ = vars[0]; }
    |   'y'     { $$ = vars[1]; }
    |   'Y'     { $$ = vars[1]; }
    |   'z'     { $$ = vars[2]; }
    |   'Z'     { $$ = vars[2]; }
    |   't'     { $$ = vars[3]; }
    |   'T'     { $$ = vars[3]; }
;

%%   /* end of grammar*/
/* C code starts here */

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <ctype.h>
#include "errlog.h"

static const char *input_string, *is;
static jmp_buf env;

void yyerror(char const *errmsg)
{
    warning_msg("bison parser sais: %s\n", errmsg);
    longjmp(env, 1);
}
   
int parse_scal(double T, const double *Pt, double *Val, const char *field_str)
{    
    vars[0] = Pt[0];
    vars[1] = Pt[1];
    vars[2] = Pt[2];
    vars[3] = T;
    vals[0] = vals[1] = vals[2] = 0.0;
    if(setjmp(env))
        return 0;
    is = input_string = field_str;
    yyparse();
    Val[0] = vals[0];
    return 1;   
}

int parse_vect(double T, const double *Pt, double *Val, const char *field_str)
{
    vars[0] = Pt[0];
    vars[1] = Pt[1];
    vars[2] = Pt[2];
    vars[3] = T;
    vals[0] = vals[1] = vals[2] = 0.0;
    if(setjmp(env))
        return 0;
    is = input_string = field_str;
    yyparse();
    Val[0] = vals[0];
    Val[1] = vals[1];
    Val[2] = vals[2];
    return 1;
}


int yylex (void)
{
    char *s;
    char c;

    /* Ignore white space, get first nonwhite character.  */
    while ( *is == ' ' || *is == '\t' || *is == '\n' ) is++;

    if (*is == EOF || *is == '\0')
        return 0;

    /* Char starts a number => parse the number.         */
    if (*is == '.' || isdigit (*is))
    {

        yylval = strtod(is, &s);
        is = s;
        return NUM;
    }

    /* The comparison operators */
    switch (*is)
    {
        case '<' :
            if (*(is+1)=='=')
            {
                is = is + 2;
                return LE;
            }
            else
            {
                is = is + 1;
                return LT;
            }
        case '>' :
            if (*(is+1)=='=')
            {
                is = is + 2;
                return GE;
            }
            else
            {
                is = is + 1;
                return GT;
            }
        case '=' :
            if (*(is+1)=='=')
                is = is + 2;
            else
                is = is + 1;
            return EQ;
        case '!' :
            if (*(is+1)=='=')
            {
                is = is + 2;
                return NE;
            }
            else
                break;
    }

    c = is[0];
    is++;
    /* Any other character is a token by itself.        */
    return c;
}

/*
int main(void)
{
    double Pt[3], Val[3];
    double T;
    char string[80];
    int keep_going = 1;
    char c;

    printf("Enter function: ");
    scanf("%s", string);
    while (keep_going)
    {
        printf("Enter X Y Z ");
        scanf("%lf %lf %lf", &Pt[0], &Pt[1], &Pt[2]);
        parse_vect(T, Pt, Val, string);
        printf("[U,V,W]=[%g,%g,%g]\n", Val[0], Val[1],Val[2]);
        scanf("%c", &c);
        if(c==EOF) return 0;
    }
    return 0;
}
*/

